//======================================================================
//    We will gone,the word kept  
//======================================================================
module pfifo_pktcnt
  #(parameter PKT_WIDTH = 16  ,
   parameter RATIO_WIDTH = 0,
   parameter ASY_CLK_ENB = "TRUE"
   )
 (
 input          m_aclk                 ,                       
 input          s_aclk                 ,  
 input          m_aresetn              ,
 input          s_aresetn              ,       
 input          s_axis_tvalid          ,          
 input          s_axis_tready          ,   
 input          s_axis_tlast           ,         
 input          m_axis_tvalid          ,          
 input          m_axis_tready          ,        
 input          m_axis_tlast           ,          
 output reg [PKT_WIDTH-1:0] m_pkt_count    ,                  
 output reg                 m_pkt_empty
 );
 //wr clk maybe faster than rd clk,&& wr_pkt_cnt add multi-pkts when rd clk'sample
 //wr clk is faster than 1'rd clk,RATIO_WIDTH=0;wr clk is faster than 2**RDTIO_WIDTH rd clk
reg  [RATIO_WIDTH:0] wr_pkt_cnt;
//reg  [RATIO_WIDTH:0] rd_pkt_cnt;
reg  [RATIO_WIDTH:0] wr_cnt_gray;
reg  [RATIO_WIDTH:0] wr_cnt_gray_rd ;
reg  [RATIO_WIDTH:0] wr_cnt_gray_rd_r ;
wire  [RATIO_WIDTH:0] wr_cnt_rd;
reg  [RATIO_WIDTH:0] wr_cnt_rd_1d;
//reg [RATIO_WIDTH:0] wr_cnt_rd_r;
reg [RATIO_WIDTH:0] wr_cnt_rd_sub;

wire rd_pkt ;// m_aclk
wire wr_pkt ;// s_aclk
assign rd_pkt = m_axis_tvalid&m_axis_tready&m_axis_tlast ;
assign wr_pkt = s_axis_tvalid&s_axis_tready&s_axis_tlast ;
generate
if (ASY_CLK_ENB == "TRUE") begin
    //******************************************
    //wr pkt,so wr_pkt_cnt add && bin2grey
    //*****************************************
    always@(negedge s_aresetn or posedge s_aclk)
        if(~m_aresetn)
            begin
                wr_pkt_cnt <= 'd0;
                wr_cnt_gray <= 'd0 ;
            end
        else if (wr_pkt==1'b1)begin 
            wr_pkt_cnt <=  wr_pkt_cnt+1 ;
            wr_cnt_gray <= bin_to_gray_conv(wr_pkt_cnt+1);
        end
    //******************************************
    //syn && grey2bin
    //*****************************************
    // synchronize write address to read clock domain
    always @(negedge m_aresetn or posedge m_aclk) begin
        if(~m_aresetn)
            begin
                wr_cnt_gray_rd   <= 'd0;
                wr_cnt_gray_rd_r <= 'd0 ;
            end
        else
            begin
                wr_cnt_gray_rd <= wr_cnt_gray;
                wr_cnt_gray_rd_r <= wr_cnt_gray_rd;
            end
    end
    //grey2bin
    assign wr_cnt_rd = gray_to_bin_conv(wr_cnt_gray_rd_r);
    //******************************************
    //get wr add pkt cnt 
    //*****************************************
    always @(negedge m_aresetn or posedge m_aclk) begin
        if(~m_aresetn)
            begin
                wr_cnt_rd_1d   <= 'd0;
                wr_cnt_rd_sub  <= 'd0 ;
            end
        else
            begin
                wr_cnt_rd_1d  <= wr_cnt_rd ;
                wr_cnt_rd_sub <= wr_cnt_rd - wr_cnt_rd_1d ;
            end
    end
end else
    always @(negedge s_aresetn or posedge s_aclk) begin
        if(~m_aresetn)
            begin
                wr_cnt_rd_sub  <= 'd0 ;
            end
        else
            begin
                wr_cnt_rd_sub <= wr_pkt ;
            end
    end
endgenerate


//******************************************
//get output rd add pkt cnt 
//*****************************************
always @(negedge m_aresetn or posedge m_aclk) begin
    if(~m_aresetn)
        begin
            m_pkt_count   <= 'd0;
            m_pkt_empty  <= 'd1 ;
        end
    else
        begin
           // m_pkt_count  <= (rd_pkt==1'b1) ? ( (m_pkt_count+1 >=wr_cnt_rd_sub) ? (m_pkt_count+1-wr_cnt_rd_sub):'d0 ) : ( (m_pkt_count >=wr_cnt_rd_sub) ? (m_pkt_count -wr_cnt_rd_sub):'d0 )  ;//cal m_pkt_count && avoid -sub to run over(no care +1 over)
            m_pkt_count  <= (rd_pkt==1'b1) ?  ((m_pkt_count+wr_cnt_rd_sub!=0)? m_pkt_count+wr_cnt_rd_sub-1 : 'd0 )  : ( m_pkt_count+wr_cnt_rd_sub)  ;//no way to compare which is bigger between m_pkt_count&wr_cnt_rd_sub;avoid pkt_cnt=0 and -1 over
            m_pkt_empty  <= (rd_pkt==1'b1) ? ( (m_pkt_count+wr_cnt_rd_sub>1) ? 1'b0 : 1'b1 ) : ( (m_pkt_count +wr_cnt_rd_sub!=0) ? 1'b0 : 1'b1) ;
        end
end


//--------------------------------------------------------
// Function: Binary to Gray Conversion
//--------------------------------------------------------
function [RATIO_WIDTH:0] bin_to_gray_conv;
input [RATIO_WIDTH:0] in;
begin
    bin_to_gray_conv = (RATIO_WIDTH=='d0) ? in[0] : {in[RATIO_WIDTH], in[RATIO_WIDTH-1:0] ^ in[RATIO_WIDTH:1]};
end
endfunction

//--------------------------------------------------------
// Function: Binary to Gray Conversion
//--------------------------------------------------------
function [RATIO_WIDTH:0] gray_to_bin_conv;
input [RATIO_WIDTH:0] gray;
integer i;
begin
    gray_to_bin_conv[RATIO_WIDTH] = gray[RATIO_WIDTH];
    for (i=RATIO_WIDTH-1; i>=0; i=i-1)
    begin
        gray_to_bin_conv[i] = (RATIO_WIDTH=='d0) ? gray[0] : gray_to_bin_conv[i+1] ^ gray[i];
    end
end
endfunction
 endmodule

